#include <sys/time.h>
#include <sstream>
#include <stdio.h>
#include <assert.h>
#include <signal.h>
#include <memory>
#include "rocket/common/log.h"
#include "rocket/common/util.h"
#include "rocket/common/config.h"
#include "rocket/net/eventloop.h"
#include "rocket/common/run_time.h"




namespace rocket {

  static Logger* g_logger = nullptr;

  void CoredumpHandler(int signal_no) {
    LOG_ERROR("progress received invalid signal, will exit");
    g_logger->flush();
    pthread_join(g_logger->getAsyncLopger()->_thread, NULL);
    pthread_join(g_logger->getAsyncAppLopger()->_thread, NULL);

    signal(signal_no, SIG_DFL);
    raise(signal_no);
  }

  Logger* Logger::GetGlobalLogger() {
    return g_logger;
  }


  Logger::Logger(LogLevel level, int type /*=1*/) : _set_level(level), _type(type) {

    if (_type == 0) {
      return;
    }
    _asnyc_logger = std::make_shared<AsyncLogger>(
            Config::GetGlobalConfig()->_log_file_name + "_rpc",
            Config::GetGlobalConfig()->_log_file_path,
            Config::GetGlobalConfig()->_log_max_file_size);

    _asnyc_app_logger = std::make_shared<AsyncLogger>(
            Config::GetGlobalConfig()->_log_file_name + "_app",
            Config::GetGlobalConfig()->_log_file_path,
            Config::GetGlobalConfig()->_log_max_file_size);
  }

  void Logger::flush() {
    syncLoop();
    _asnyc_logger->stop();
    _asnyc_logger->flush();

    _asnyc_app_logger->stop();
    _asnyc_app_logger->flush();
  }


  void Logger::init() {
    if (_type == 0) {
      return;
    }
    // 配置文件中写的0.5s 刷新太慢了（对于测试文件来说）
    _timer_event = std::make_shared<TimerEvent>(Config::GetGlobalConfig()->_log_sync_inteval, std::bind(&Logger::syncLoop, this), true);
    EventLoop::GetCurrentEventLoop()->addTimerEvent(_timer_event);
    signal(SIGSEGV, CoredumpHandler);
    signal(SIGABRT, CoredumpHandler);
    signal(SIGTERM, CoredumpHandler);
    signal(SIGKILL, CoredumpHandler);
    signal(SIGINT, CoredumpHandler);
    signal(SIGSTKFLT, CoredumpHandler);

  }


  void Logger::syncLoop() {
    // 同步 _buffer 到 async_logger 的buffer队尾
    // printf("sync to async logger\n");
    std::vector<std::string> tmp_vec;
    ScopeMutex<Mutex> lock(_mutex);
    tmp_vec.swap(_buffer);
    lock.unlock();

    if (!tmp_vec.empty()) {
      _asnyc_logger->pushLogBuffer(tmp_vec);
    }
    tmp_vec.clear();

    // 同步 _app_buffer 到 app_async_logger 的buffer队尾
    std::vector<std::string> tmp_vec2;
    ScopeMutex<Mutex> lock2(_app_mutex);
    tmp_vec2.swap(_app_buffer);
    lock.unlock();

    if (!tmp_vec2.empty()) {
      _asnyc_app_logger->pushLogBuffer(tmp_vec2);
    }

  }


  void Logger::InitGlobalLogger(int type /*=1*/) {

    LogLevel global_log_level = StringToLogLevel(Config::GetGlobalConfig()->_log_level);
    printf("Init log level [%s]\n", LogLevelToString(global_log_level).c_str());
    g_logger = new Logger(global_log_level, type);
    g_logger->init();

  }



  std::string LogLevelToString(LogLevel level) {
    switch (level) {
      case Debug:
        return "DEBUG";

      case Info:
        return "INFO";

      case Error:
        return "ERROR";
      default:
        return "UNKNOWN";
    }
  }


  LogLevel StringToLogLevel(const std::string& log_level) {
    if (log_level == "DEBUG") {
      return Debug;
    } else if (log_level == "INFO") {
      return Info;
    } else if (log_level == "ERROR") {
      return Error;
    } else {
      return Unknown;
    }
  }

  std::string LogEvent::toString() {
    struct timeval now_time;

    gettimeofday(&now_time, nullptr);

    struct tm now_time_t;
    localtime_r(&(now_time.tv_sec), &now_time_t);

    char buf[128];
    strftime(&buf[0], 128, "%y-%m-%d %H:%M:%S", &now_time_t);
    std::string time_str(buf);
    int ms = now_time.tv_usec / 1000;
    time_str = time_str + "." + std::to_string(ms);


    _pid = getPid();
    _thread_id = getThreadId();

    std::stringstream ss;

    ss << "[" << LogLevelToString(_level) << "]\t"
       << "[" << time_str << "]\t"
       << "[" << _pid << ":" << _thread_id << "]\t";

    // 获取当前线程处理的请求的 msgid

    std::string msgid = RunTime::GetRunTime()->_msgid;
    std::string method_name = RunTime::GetRunTime()->_method_name;
    if (!msgid.empty()) {
      ss << "[" << msgid << "]\t";
    }

    if (!method_name.empty()) {
      ss << "[" << method_name << "]\t";
    }
    return ss.str();
  }



  void Logger::pushLog(const std::string& msg) {
    if (_type == 0) {
      printf((msg + "\n").c_str());
      return;
    }
    ScopeMutex<Mutex> lock(_mutex);
    // printf("push_back something");
    _buffer.push_back(msg);
    lock.unlock();
  }

  void Logger::pushAppLog(const std::string& msg) {
    ScopeMutex<Mutex> lock(_app_mutex);
    _app_buffer.push_back(msg);
    lock.unlock();
  }


  void Logger::log() {

  }


  AsyncLogger::AsyncLogger(const std::string& file_name, const std::string& file_path, int max_size)
          : _file_name(file_name), _file_path(file_path), _max_file_size(max_size) {

    sem_init(&_sempahore, 0, 0);

    assert(pthread_create(&_thread, nullptr, &AsyncLogger::Loop, this) == 0);

    // assert(pthread_cond_init(&_condtion, NULL) == 0);

    sem_wait(&_sempahore);

  }


  void* AsyncLogger::Loop(void* arg) {
    // 将 buffer 里面的全部数据打印到文件中，然后线程睡眠，直到有新的数据再重复这个过程

    AsyncLogger* logger = reinterpret_cast<AsyncLogger*>(arg);

    assert(pthread_cond_init(&logger->_condtion, nullptr) == 0);

    sem_post(&logger->_sempahore);

    while(1) {
      ScopeMutex<Mutex> lock(logger->_mutex);
      while(logger->_buffer.empty()) {
        // printf("begin pthread_cond_wait back \n");
        pthread_cond_wait(&(logger->_condtion), logger->_mutex.getMutex());
      }
      // printf("pthread_cond_wait back \n");

      std::vector<std::string> tmp;
      tmp.swap(logger->_buffer.front());
      logger->_buffer.pop();

      lock.unlock();

      timeval now;
      gettimeofday(&now, NULL);

      struct tm now_time;
      localtime_r(&(now.tv_sec), &now_time);

      const char* format = "%Y%m%d";
      char date[32];
      strftime(date, sizeof(date), format, &now_time);

      if (std::string(date) != logger->_date) {
        logger->_no = 0;
        logger->_reopen_flag = true;
        logger->_date = std::string(date);
      }
      if (logger->_file_hanlder == NULL) {
        logger->_reopen_flag = true;
      }

      std::stringstream ss;
      ss << logger->_file_path << logger->_file_name << "_"
         << std::string(date) << "_log.";
      std::string log_file_name = ss.str() + std::to_string(logger->_no);

      if (logger->_reopen_flag) {
        if (logger->_file_hanlder) {
          fclose(logger->_file_hanlder);
        }
        logger->_file_hanlder = fopen(log_file_name.c_str(), "a");
        logger->_reopen_flag = false;
      }

      if (ftell(logger->_file_hanlder) > logger->_max_file_size) {
        fclose(logger->_file_hanlder);

        log_file_name = ss.str() + std::to_string(logger->_no++);
        logger->_file_hanlder = fopen(log_file_name.c_str(), "a");
        logger->_reopen_flag = false;

      }

      for (auto& i : tmp) {
        if (!i.empty()) {
          fwrite(i.c_str(), 1, i.length(), logger->_file_hanlder);
        }
      }
      fflush(logger->_file_hanlder);

      if (logger->_stop_flag) {
        return nullptr;
      }
    }

  }


  void AsyncLogger::stop() {
    _stop_flag = true;
  }

  void AsyncLogger::flush() {
    if (_file_hanlder) {
      fflush(_file_hanlder);
    }
  }

  void AsyncLogger::pushLogBuffer(std::vector<std::string>& vec) {
    ScopeMutex<Mutex> lock(_mutex);
    _buffer.push(vec);
    pthread_cond_signal(&_condtion);

    lock.unlock();

    // 这时候需要唤醒异步日志线程
    // printf("pthread_cond_signal\n");
  }

}